#include "Generate_C_std.h"


#include "Pattern_class_def.h"

bool Pattern_class_def::match(Statement* that)
{
  use_scope = false;
  pattern = new Wildcard<Class_def>;
  return that->match(pattern);
}

void Pattern_class_def::generate_code(Generate_C* gen)
{
  // Compile the class members
  foreach (Member* member, *pattern->value->members)
    {
      Method* method = dynamic_cast<Method*>(member);
      
      if(method != NULL)
	{
	  buf << gen->compile_statement(method);
	} 
    }
  
  // Declare all class members
  function_declaration_block(buf, pattern->value->attrs->get_list<Signature>("phc.codegen.compiled_functions"), pattern->value->class_name->value);
  
  // Create the class entry in MINIT
  ostream & minit = GetMInit();
  minit
    << "{\n"
    << "zend_class_entry ce; // temp\n"
    << "zend_class_entry* ce_reg; // once registered, ce_ptr should be used\n"
    << "INIT_CLASS_ENTRY(ce, " 
    << "\"" << *pattern->value->class_name->value << "\", " 
    << *pattern->value->class_name->value << "_functions);\n"
    ;
  SetMInit(minit);


  // Register the class
  CLASS_NAME* parent = pattern->value->extends;
  if(parent != NULL)
    {
      minit 
	<< "zend_class_entry* parent;\n"
	<< "parent = zend_fetch_class(\"" << *parent->value << "\", " << parent->value->length() << ", ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC);\n"
	<< "ce_reg = zend_register_internal_class_ex(&ce, parent, \"" << *parent->value << "\" TSRMLS_CC);\n";
      ;
    }
  else
    {
      minit << "ce_reg = zend_register_internal_class(&ce TSRMLS_CC);\n";
    }

  // Clear the ZEND_INTERNAL_CLASS flag so that we can add complex zvals
  // as class attributes. TODO: not sure what the consequences of this are.
  minit << "ce_reg->type &= ~ZEND_INTERNAL_CLASS;\n";

  // Compile attributes
  foreach (Member* member, *pattern->value->members)
    {
      Attribute* attr = dynamic_cast<Attribute*>(member);

      if(attr != NULL)
	{
	  minit << "{\n";
				
	  // We must have a default value
	  assert(attr->var->default_value != NULL);
	  gen->compile_static_value("default_value", minit, attr->var->default_value);

	  if(!attr->attr_mod->is_const)
	    {
	      minit 
		<< "phc_declare_property(ce_reg, "
		<< "\"" << *attr->var->variable_name->value << "\", " 
		<< attr->var->variable_name->value->size() << ", "
		<< "default_value, "
		<< attr_mod_flags(attr->attr_mod) << " " 
		<< "TSRMLS_CC);"
		;
	    }
	  else if(attr->attr_mod->is_const)
	    {
	      // TODO: implement
	      // (Const attributes must be added using a different API)
	      //	      phc_unsupported (attr, "const
	      // attribute");
	      minit 
		<< "MyDeclareConst(ce_reg, "
		<< "\"" << *attr->var->variable_name->value << "\", " 
		<< attr->var->variable_name->value->size() << ", "
		<< "default_value, "
		<< attr_mod_flags(attr->attr_mod) << " " 
		<< "TSRMLS_CC);"
		;


	    }

	  minit << "}";
	}
    }

  minit << "}";
}


CREATE(Pattern_class_def)
